package controllers

import dao.{AnnoDao, BasicDao}
import play.api.cache.AsyncCacheApi
import play.api.libs.json.Json
import play.api.mvc._
import play.api.routing.JavaScriptReverseRouter
import tool.FormTool
import utils.Utils

import scala.concurrent.ExecutionContext.Implicits.global
import javax.inject.Inject
import models.Tables._
import tool.Pojo.KeywordInfo
import implicits.Implicits._
import org.apache.commons.lang3.StringUtils


/**
 * Created by yz on 16/9/2021
 */
class GenomeController @Inject()(cc: ControllerComponents, cache: AsyncCacheApi)(
  implicit val basicDao: BasicDao,
  implicit val annoDao: AnnoDao
) extends AbstractController(cc) {

  def toIndex = Action { implicit request =>
    Ok(views.html.genome.index())
  }

  def searchBefore = Action { implicit request =>
    Ok(views.html.genome.search(None))
  }

  def searchBefore1 = Action { implicit request =>
    val data = FormTool.geneIdForm.bindFromRequest().get
    val geneId = if (StringUtils.isBlank(data.geneId)) "XP_042499423.1" else data.geneId
    Ok(views.html.genome.search(Some(geneId)))
  }

  def searchByGeneId = Action.async { implicit request =>
    val data = FormTool.geneIdForm.bindFromRequest.get
    val species = FormTool.speciesForm.bindFromRequest().get.species
    val geneIds = data.geneId.split(",").distinct
    basicDao.selectByGeneIds(geneIds, species).map { x =>
      val array = Utils.getArrayByTs(x)
      Ok(Json.toJson(array))
    }
  }

  def getAllGeneIds = Action.async {
    basicDao.selectAllGeneIds.map { x =>
      Ok(Json.toJson(x))
    }
  }

  def searchByGeneName = Action.async { implicit request =>
    val data = FormTool.geneNameForm.bindFromRequest.get
    val species = FormTool.speciesForm.bindFromRequest().get.species
    val geneNames = data.geneName.split(",").distinct
    basicDao.selectByGeneNames(geneNames, species).map { x =>
      val array = Utils.getArrayByTs(x)
      Ok(Json.toJson(array))
    }
  }

  def getAllGeneNames = Action.async {
    basicDao.selectAllGeneNames.map { x =>
      val geneNames = x.distinct
      Ok(Json.toJson(geneNames))
    }
  }

  def searchByRegion = Action.async { implicit request =>
    val data = FormTool.regionForm.bindFromRequest.get
    val species = FormTool.speciesForm.bindFromRequest().get.species
    basicDao.selectByRegionData(data).map { x =>
      val array = Utils.getArrayByTs(x)
      Ok(Json.toJson(array))
    }
  }

  def getAllChrs = Action.async { implicit request =>
    val species = FormTool.speciesForm.bindFromRequest().get.species
    basicDao.selectAllChrs(species).map { x =>
      Ok(Json.toJson(x))
    }
  }

  def searchByKeyword = Action.async { implicit request =>
    val data = FormTool.keywordForm.bindFromRequest.get
    val keywords = data.keyword.trim.split("\\s+").toBuffer.distinct
    cache.getOrElseUpdate[Seq[BasicRow]]("basics")(basicDao.selectAll).flatMap { case x =>
      val keywordsMap = x.map { y =>
        (y, KeywordInfo(keywords, Map[String, String]()))
      }.toMap
      val searchMap = Utils.getSearchMap(keywordsMap, "id", Seq("id", "geneName", "description", "locus"))
      val ids = searchMap.keys.toList
      val getAnnoMapF = annoDao.selectAll.map { rows =>
        rows.map { row =>
          (row.id, row)
        }.toMap
      }
      cache.getOrElseUpdate[Map[String, AnnoRow]]("annoMap")(getAnnoMapF).map { x =>
        ids.map { id =>
          x(id)
        }.map(y => (y, searchMap(y.id))).toMap
      }
    }.map { infos =>
      val searchMap = Utils.getSearchMap(infos, "id", Seq("ko", "gos"))
      val array = searchMap.filter(x => x._2.remainKeywords.size == 0).map { case (geneId, keywordInfo) =>
        Json.obj("id" -> geneId, "match" -> Json.toJson(keywordInfo.map))
      }
      val json = Json.obj("columnNames" -> List("id", "match"), "array" -> array)
      Ok(json)
    }
  }

  def getBasicInfo = Action.async { implicit request =>
    val data = FormTool.geneIdForm.bindFromRequest().get
    basicDao.selectBasicByGeneId(data.geneId).map { x =>
      val array = Utils.getMapByT(x)
      Ok(Json.toJson(array))
    }
  }

  def getAllBasic = Action.async { implicit request =>
    basicDao.selectAll.map { x =>
      val json = Utils.getJsonByTs(x)
      Ok(json)
    }
  }

}
